package com.wanghaoran.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.wanghaoran.dto.*;
import com.wanghaoran.entity.Assets;
import com.wanghaoran.entity.AssetsBorrow;
import com.wanghaoran.excel.AssetsBorrowExcel;
import com.wanghaoran.exception.IllegalParamException;
import com.wanghaoran.exception.ServerErrorException;
import com.wanghaoran.exception.VersionException;
import com.wanghaoran.mapper.AssetsBorrowMapper;
import com.wanghaoran.mapper.AssetsMapper;
import com.wanghaoran.service.AssetsBorrowService;
import com.wanghaoran.vo.AssetsBorrowVO;
import jakarta.annotation.Resource;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author wanghaoran
 */
@Service
@CacheConfig(cacheNames = {"assetsBorrow", "assets"})
public class AssetsBorrowServiceImpl implements AssetsBorrowService {

    @Resource
    private AssetsBorrowMapper assetsBorrowMapper;

    @Resource
    private AssetsMapper assetsMapper;


    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(allEntries = true)
    @Override
    public synchronized int insert(AssetsBorrowInsertDTO dto) {
        String info = dto.getInfo();
        Long fkAssetsId = dto.getFkAssetsId();
        Integer count = dto.getCount();
        // 判断申请时间和预计归还时间
        if (dto.getBorrowTime().isAfter(dto.getExpectedReturnTime())) {
            throw new IllegalParamException("申请时间不能晚于预计归还时间");
        }
        // 查询资产信息
        Assets assets = assetsMapper.select(fkAssetsId);
        if (ObjectUtil.isNull(assets)) {
            throw new ServerErrorException("资产不存在");
        }
        // 判断剩余库存是否充足
        Integer stock = assets.getStock();
        String stockUnit = assets.getStockUnit();
        if (count > stock) {
            throw new IllegalParamException("库存不足，仅剩" + stock + stockUnit);
        }
        // 拷贝属性
        AssetsBorrow assetsBorrow = BeanUtil.copyProperties(dto, AssetsBorrow.class);

        // 设置默认值
        assetsBorrow.setInfo(StrUtil.isBlank(info) ? "暂无描述" : info);
        assetsBorrow.setVersion(0L);
        assetsBorrow.setDeleted(0);
        assetsBorrow.setCreated(LocalDateTime.now());
        assetsBorrow.setUpdated(LocalDateTime.now());

        // DB添加：添加申请记录
        int insertResult = assetsBorrowMapper.insert(assetsBorrow);
        if (insertResult <= 0) {
            throw new ServerErrorException("DB添加失败");
        }
        // DB修改：扣减库存
        stock -= count;
        assets.setStock(stock);
        int updateResult = assetsMapper.update(assets);
        if (updateResult <= 0) {
            throw new ServerErrorException("DB修改失败");
        }
        return insertResult + updateResult;
    }


    @Cacheable(key = "#p0", condition = "#p0 != null", unless = "#result == null")
    @Override
    public AssetsBorrow select(Long id) {
        AssetsBorrow result = assetsBorrowMapper.select(id);
        if(ObjectUtil.isNull(result)) {
            throw new ServerErrorException("ID不存在");
        }
        return result;
    }

    @Cacheable(key = "#root.methodName", unless = "#result == null")
    @Override
    public List<AssetsBorrowVO> list() {
        return assetsBorrowMapper.list(new AssetsBorrowPageDTO())
                .stream()
                .map(assetsBorrow -> BeanUtil.copyProperties(assetsBorrow, AssetsBorrowVO.class))
                .collect(Collectors.toList());
    }

    @Cacheable(key = "#root.methodName + ':' + #p0.toString()",
            condition = "#p0 != null",
            unless = "#result == null")
    @Override
    public PageInfo<AssetsBorrow> page(AssetsBorrowPageDTO dto) {
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        return new PageInfo<>(assetsBorrowMapper.list(dto));
    }



    @CacheEvict(allEntries = true)
    @Transactional
    @Retryable(retryFor = VersionException.class)
    @Override
    public int update(AssetsBorrowUpdateDTO dto) {
        Long id = dto.getId();
        if (ObjectUtil.isNull(id)) {
            throw new IllegalParamException("ID为空");
        }
        AssetsBorrow assetsBorrow = assetsBorrowMapper.select(id);
        if (ObjectUtil.isNull(assetsBorrow)) {
            throw new ServerErrorException("记录不存在");
        }
        BeanUtil.copyProperties(dto, assetsBorrow);

        // 判断申请时间和预计归还时间
        if (dto.getBorrowTime().isAfter(dto.getExpectedReturnTime())) {
            throw new IllegalParamException("申请时间不能晚于预计归还时间");
        }

        if (StrUtil.isBlank(assetsBorrow.getInfo())) {
            assetsBorrow.setInfo("暂无描述");
        }
        assetsBorrow.setUpdated(LocalDateTime.now());

        int result = assetsBorrowMapper.update(assetsBorrow);
        if (result <= 0) {
            throw new VersionException("DB修改失败");
        }
        return result;
    }


    @CacheEvict(allEntries = true)
    @Override
    public int delete(Long id) {
        int result = assetsBorrowMapper.delete(id);
        if (result <= 0) {
            throw new ServerErrorException("DB删除失败");
        }
        return result;
    }

    @CacheEvict(allEntries = true)
    @Override
    public int deleteBatch(List<Long> ids) {
        int result = assetsBorrowMapper.deleteBatch(ids);
        if (result <= 0) {
            throw new ServerErrorException("DB批量删除失败");
        }
        return result;
    }

    @Override
    public List<AssetsBorrowExcel> getExcelData() {
        return assetsBorrowMapper.list(new AssetsBorrowPageDTO())
                .stream()
                .map(assetsBorrow -> {
                    AssetsBorrowExcel assetsBorrowExcel = new AssetsBorrowExcel();
                    BeanUtil.copyProperties(assetsBorrow, assetsBorrowExcel);
                    if(ObjectUtil.isNotNull(assetsBorrow.getAssets())) {
                        assetsBorrowExcel.setAssetsTitle(assetsBorrow.getAssets().getTitle());
                    }
                    if(ObjectUtil.isNotNull(assetsBorrow.getEmp())) {
                        assetsBorrowExcel.setEmpName(assetsBorrow.getEmp().getRealname());
                    }
                    assetsBorrowExcel.setIsReturn(ObjectUtil.isNotNull(assetsBorrow.getReturnTime()) ? "已归还": "未归还");
                    return assetsBorrowExcel;
                })
                .collect(Collectors.toList());
    }

    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int returnAssets(Long id) {
        AssetsBorrow assetsBorrow = assetsBorrowMapper.select(id);
        if (ObjectUtil.isNotNull(assetsBorrow.getReturnTime())) {
            throw new IllegalParamException("资产已归还");
        }
        assetsBorrow.setReturnTime(LocalDateTime.now());
        assetsBorrowMapper.update(assetsBorrow);
        Assets assets = assetsMapper.select(assetsBorrow.getFkAssetsId());
        if (ObjectUtil.isNull(assets)) {
            throw new ServerErrorException("资产不存在");
        }
        assets.setStock(assetsBorrow.getCount() + assets.getStock());
        int result = assetsMapper.update(assets);
        if (result < 0) {
            throw new IllegalParamException("资产归还失败");
        }
        return result;
    }
}
